#include "s_sd3077.h"

#include <stdio.h>
#include <string.h>

#include "s_utc_2_normaltime.h"

#define S_SD3077_IIC_ADDR                               0x32//0x64//0x32

#define S_SD3077_TIME_START_ADDR                        0x00
#define S_SD3077_TIME_DATA_LEN                          0x07

#define S_SD3007_CRTL1_ADDR                             0x0F
#define S_SD3007_CRTL2_ADDR                             0x10
#define S_SD3007_CRTL3_ADDR                             0x11

//#define S_SD3007_CRTL_DATA_LEN                  0x02

#define S_SD3007_WRTC1_BIT                              0x80
#define S_SD3007_WRTC2_BIT                              0x04
#define S_SD3007_WRTC3_BIT                              0x80

#define S_SD3007_CLOCK_ALARM_SEC_ADDR                   0x07
#define S_SD3007_CLOCK_ALARM_MIN_ADDR                   0x08
#define S_SD3007_CLOCK_ALARM_HOUR_ADDR                  0x09

#define S_SD3007_CLOCK_ALARM_ENABLE_ADDR                0x0E

// #define S_SD3007_CRTL1_ADDR                            0x0F
// #define S_SD3007_CRTL2_ADDR                            0x10

// #define S_SD3007_CTRL_2_IM_BIT                  0b01000000
// #define S_SD3007_CTRL_2_INTS1_BIT               0b00100000
// #define S_SD3007_CTRL_2_INTS0_BIT               0b00010000
#define S_SD3007_CTRL_2_CLOCK_ALARM_SINGLE_INT_MODE     0x52 //0x12 //0b00010010

/*
#define S_SD3007_WRTC1_BIT_NO                   0x7F
#define S_SD3007_WRTC2_BIT_NO                   0xFB
#define S_SD3007_WRTC3_BIT_NO                      0x7F
*/

////////////////////////////////////////////////////////////////////////////////
#include "h_cc2640r2f_iic.h"
//#include "h_cc2640r2f_iics.h"
#include "h_cc2640r2f_define.h"
#include "h_cc2640r2f_simpletime.h"


#define s_sd3077_iic_readbuff(x,y,z)             \
        H_CC2640R2F_IIC_ReadBuffer(S_SD3077_IIC_ADDR,x,y,z)
#define s_sd3077_iic_writebuff(x,y,z)            \
        H_CC2640R2F_IIC_WriteBuffer(S_SD3077_IIC_ADDR,x,y,z)
             
#define s_sd3077_debug                          printf
////////////////////////////////////////////////////////////////////////////////
#define S_SD3077_Byte2BCD(x)		(x > 9 ? ((x/10)<<4) + (x % 10): x)
#define S_SD3077_BCD2Byte(x)		(x > 0x0F ? ((x >> 4) * 10) + (x & 0x0F): x)       

#if UTC_GET_SHOW_TIME
static void s_utc2normaltime_str_show(p_s_normaltime_str nmt)
{
	if(NULL == nmt)
	{
		return;
	}
	s_sd3077_debug("The time is %d-%02d-%02d %02d:%02d:%02d(%d)\r\n", nmt->year, nmt->month, nmt->day, nmt->hour, nmt->min, nmt->sec, nmt->weeknum);
}
#endif

signed char S_SD3077_GetDateStr(p_s_normaltime_str nmt)
{
    unsigned char rdata[S_SD3077_TIME_DATA_LEN];
    signed char rslt = 0;

    rslt = s_sd3077_iic_readbuff(S_SD3077_TIME_START_ADDR, rdata, S_SD3077_TIME_DATA_LEN);

    if(rslt == 0)
    {
        //Get second
        nmt->sec = S_SD3077_BCD2Byte(rdata[0]);
        //Get min
        nmt->min = S_SD3077_BCD2Byte(rdata[1]);
        //Get hour
        //Reduce 24hour flag
        rdata[2] &= 0x7F;
        nmt->hour = S_SD3077_BCD2Byte(rdata[2]);
        //Get week num
        nmt->weeknum = rdata[3];
        //Get day
        nmt->day = S_SD3077_BCD2Byte(rdata[4]);
        //Get month
        nmt->month = S_SD3077_BCD2Byte(rdata[5]);
        //Get year
        nmt->year = S_SD3077_BCD2Byte(rdata[6]);
        nmt->year += 2000;

#if UTC_GET_SHOW_TIME
        
#endif
    }
    else
    {
        //Get second
        nmt->sec = S_SD3077_BCD2Byte(rdata[0]);
        //Get min
        nmt->min = S_SD3077_BCD2Byte(rdata[1]);
        //Get hour
        //Reduce 24hour flag
        rdata[2] &= 0x7F;
        nmt->hour = S_SD3077_BCD2Byte(rdata[2]);
        //Get week num
        nmt->weeknum = rdata[3];
        //Get day
        nmt->day = S_SD3077_BCD2Byte(rdata[4]);
        //Get month
        nmt->month = S_SD3077_BCD2Byte(rdata[5]);
        //Get year
        nmt->year = S_SD3077_BCD2Byte(rdata[6]);
        nmt->year += 2000;
#if !LOCK_BOARD_RELEASE
        s_sd3077_debug("SD3077 str Read failed\r\n");
#endif
    }

    // s_utc2normaltime_str_show(nmt);


    return rslt;
}

static signed char s_sd3077_write_enable(void)
{
    signed char rslt = 0;
    unsigned char data[2];
    
    rslt += s_sd3077_iic_readbuff(S_SD3007_CRTL1_ADDR, data, 2);

    // printf("data is 0x%02x, %02x\r\n", data[0], data[1]);

    //CTRL 2 reg first for Write-1
    data[1] ^= S_SD3007_WRTC1_BIT;
    rslt += s_sd3077_iic_writebuff(S_SD3007_CRTL2_ADDR, &data[1], 1);
    //CTRL 1 reg for Write-3 and write-2
    data[0] ^= S_SD3007_WRTC2_BIT + S_SD3007_WRTC3_BIT;
    rslt += s_sd3077_iic_writebuff(S_SD3007_CRTL1_ADDR, data, 1);

    // printf("data is 0x%02x, %02x\r\n", data[0], data[1]);

    
    return rslt;
}

static signed char s_sd3077_write_disable(void)
{
    signed char rslt = 0;
    unsigned char data[1];

    rslt += s_sd3077_iic_readbuff(S_SD3007_CRTL1_ADDR, data, 2);

    // CTRL 1 reg firts for Write-3 and write-2
    data[0] &= ~(S_SD3007_WRTC2_BIT + S_SD3007_WRTC3_BIT);
    rslt += s_sd3077_iic_writebuff(S_SD3007_CRTL1_ADDR, data, 1);
    // CRTL 2 reg for Write-1
    data[1] &= ~(S_SD3007_WRTC1_BIT);
    rslt += s_sd3077_iic_writebuff(S_SD3007_CRTL2_ADDR, &data[1], 1);
    
    
    return rslt;
}


signed char S_SD3077_SetDate(unsigned int utc)
{
    signed char rslt = 0;
    
    unsigned char wdata[S_SD3077_TIME_DATA_LEN];
    
    s_normaltime_str nmt;

    //Change utc time to normal time
    S_UTC2NormalTime(utc, &nmt);
  
    //Set second
    wdata[0] = S_SD3077_Byte2BCD(nmt.sec);
    //Set min
    wdata[1] = S_SD3077_Byte2BCD(nmt.min);
    //Set hour
    wdata[2] = S_SD3077_Byte2BCD(nmt.hour);
    //Enable 24 hour mode
    wdata[2] |= 0x80;
    //Set Week num
    wdata[3] = S_SD3077_Byte2BCD(nmt.weeknum);
    //Set day
    wdata[4] = S_SD3077_Byte2BCD(nmt.day);
    //Set month
    wdata[5] = S_SD3077_Byte2BCD(nmt.month);
    //Set year
    nmt.year -= 2000;
    wdata[6] = S_SD3077_Byte2BCD(nmt.year);
 
    //s_sd3077_debug("The write datas is %d %d %d %d %d %d %d\r\n", wdata[0], wdata[1], wdata[2], wdata[3], wdata[4], wdata[5], wdata[6]);
//    s_sd3077_debug("The write datas is %d %d %d %d %d %d %d\r\n", nmt.year, nmt.month, nmt.day, nmt.hour, nmt.min, nmt.sec);

    rslt = s_sd3077_write_enable();
    
    rslt += s_sd3077_iic_writebuff(S_SD3077_TIME_START_ADDR, wdata, \
                                    S_SD3077_TIME_DATA_LEN);
     
    if(rslt == 0)
    {
        
        if(rslt == 0)
        {
//            s_sd3077_debug("Set time success\r\n");
            s_sd3077_write_disable();
            return rslt;
        }
        else
        {
//            s_sd3077_debug("Set time failed\r\n");
        }
    }
    else
    {
//        s_sd3077_debug("Set status failed\r\n");
    }
    

    s_sd3077_write_disable();
    
    return rslt;
}

signed char S_SD3077_GetDate(unsigned int *utc)
{
    unsigned char rdata[S_SD3077_TIME_DATA_LEN];
    signed char rslt = 0;
    s_normaltime_str nmt;
    
    rslt = s_sd3077_iic_readbuff(S_SD3077_TIME_START_ADDR, rdata, S_SD3077_TIME_DATA_LEN);
    
    if(rslt == 0)
    {
        //Get second
        nmt.sec = S_SD3077_BCD2Byte(rdata[0]);
        //Get min
        nmt.min = S_SD3077_BCD2Byte(rdata[1]);
        //Get hour
        //Reduce 24hour flag
        rdata[2] &= 0x7F;
        nmt.hour = S_SD3077_BCD2Byte(rdata[2]);
        //Get week num
        nmt.weeknum = rdata[3];
        //Get day
        nmt.day = S_SD3077_BCD2Byte(rdata[4]);
        //Get month
        nmt.month = S_SD3077_BCD2Byte(rdata[5]);
        //Get year
        nmt.year = S_SD3077_BCD2Byte(rdata[6]);
        nmt.year += 2000;
        
#if UTC_GET_SHOW_TIME
        s_utc2normaltime_str_show(nmt);
#endif
        
        S_NormalTime2UTC(&nmt, utc);
    }
    else
    {
#if !LOCK_BOARD_RELEASE
        s_sd3077_debug("SD3077 Read failed\r\n");
#endif
    }
    
    
    return rslt;
}




signed char S_SD3077_Set_ClockAlarm_IntPin(void)
{
    signed char rslt = 0;

    unsigned char wdata[1]; //{S_SD3007_CTRL_2_CLOCK_ALARM_SINGLE_INT_MODE};

    

    rslt += s_sd3077_iic_readbuff(S_SD3007_CRTL2_ADDR, wdata, \
                                    1);

    // printf("the ctr2(0x%02x) data is 0x%02x\n", S_SD3007_CRTL2_ADDR, wdata[0]);

    // WCTR1 enable
    wdata[0] |= 0x80; // 0b10000000

    // IM : single(0) or period(1)
    wdata[0] |= 0x40; //0b01000000
    // wdata[0] &= ~(0x40); //0b01000000

    // Pin for clock alarm
    wdata[0] &= ~(0x20); //0b00100000
    wdata[0] |= 0x10; //0b00010000

    // CountDown disable
    wdata[0] &= ~(0x04); //0b00000100
    // Alarm clock enable
    wdata[0] |= 0x02; //0b00000010
    // Disbale frequente alarm
    wdata[0] &= ~(0x01); //0b00000001

    // printf("the pin mode is 0x%02x, addr is 0x%02x\r\n", wdata[0], S_SD3007_CRTL2_ADDR);


    rslt = s_sd3077_write_enable();
    
    rslt += s_sd3077_iic_writebuff(S_SD3007_CRTL2_ADDR, wdata, \
                                    1);

    s_sd3077_write_disable();

    H_CC2640R2F_SimpleTime_Around_Delay(10);

    return rslt;
}

// signed char S_SD3077_Set_ClockAlarmMode_IntFlag_ReadClear_Mode(void)
// {
//     signed char rslt = 0;

//     unsigned char wdata[1];

//     rslt += s_sd3077_iic_readbuff(S_SD3007_CRTL3_ADDR, wdata, \
//                                     1);

//     printf("the ctr3(0x%02x) is 0x%02x\r\n", S_SD3007_CRTL3_ADDR, wdata[0]);

//     // Set ARST to 1 so read ctr1 register will clear interrupt-flag
//     wdata[0] |= 0x80; //0b10000000

//     rslt = s_sd3077_write_enable();
    
//     rslt += s_sd3077_iic_writebuff(S_SD3007_CRTL3_ADDR, wdata, \
//                                     1);

//     s_sd3077_write_disable();

//     H_CC2640R2F_SimpleTime_Around_Delay(10);


//     return rslt;
// }

signed char S_SD3077_Set_ClockAlarmMode(sd3077_clock_alarm_mode mode)
{
    signed char rslt = 0;

    unsigned char wdata[1] = {mode};

    // printf("the clock mode is 0x%02x, addr is 0x%02x\n", wdata[0], S_SD3007_CLOCK_ALARM_ENABLE_ADDR);

    rslt = s_sd3077_write_enable();
    
    rslt += s_sd3077_iic_writebuff(S_SD3007_CLOCK_ALARM_ENABLE_ADDR, wdata, \
                                    1);

    rslt += s_sd3077_write_disable();

    H_CC2640R2F_SimpleTime_Around_Delay(10);

    // printf("set mode rslt is %d\r\n", rslt);

    rslt += S_SD3077_Set_ClockAlarm_IntPin();

    

    // printf("set pin rslt is %d\r\n", rslt);

    return rslt;
}


signed char S_SD3077_Clear_IntrFlag(void)
{
    signed char rslt = 0;

    unsigned char rdata[1];

    rslt = s_sd3077_iic_readbuff(S_SD3007_CRTL1_ADDR, rdata, 1);

    // printf("the intaf is %d in ctr1\r\n", ((rdata[0] & 0x20) != 0 ? 1 : 0));

    // Reset intr alarm flag
    rdata[0] &= ~(0x20);
    // Enable Write bit 2 and 3
    rdata[0] |= 0x80;
    rdata[0] |= 0x04;

    rslt = s_sd3077_write_enable();
    
    rslt += s_sd3077_iic_writebuff(S_SD3007_CRTL1_ADDR, rdata, \
                                    1);

    rslt += s_sd3077_write_disable();

    H_CC2640R2F_SimpleTime_Around_Delay(10);

    // rslt = s_sd3077_iic_readbuff(S_SD3007_CRTL1_ADDR, rdata, 1);

    // printf("the intaf is %d in ctr1\r\n", ((rdata[0] & 0x20) != 0 ? 1 : 0));
    

    return rslt;
}


signed char S_SD3077_SetInt_Hour_Min_Second_ByDaySeconds(unsigned int secs)
{
    signed char rslt = 0;

    SD3077_HMS_Data hms;

    unsigned char wdata[3];
#if !LOCK_BOARD_RELEASE
    printf("the time sec is %d\r\n", secs);
#endif
    if(secs >= SD3077_IMPOSSIBLE_TIME)
    {
        secs = SD3077_IMPOSSIBLE_TIME;
    }

    S_SD3077_Seconds_2_HMS(secs, &hms);
#if !LOCK_BOARD_RELEASE
    printf("time: %d:%d:%d\r\n", hms.hour, hms.min, hms.sec);
#endif
    wdata[0] = S_SD3077_Byte2BCD(hms.sec);
    wdata[1] = S_SD3077_Byte2BCD(hms.min);
    wdata[2] = S_SD3077_Byte2BCD(hms.hour);

    // printf("the sec bcd is 0x%02x, addr is 0x%02x\r\n", wdata[0], S_SD3007_CLOCK_ALARM_SEC_ADDR);

    rslt = s_sd3077_write_enable();
    
    rslt += s_sd3077_iic_writebuff(S_SD3007_CLOCK_ALARM_SEC_ADDR, wdata, \
                                    3);



    rslt += s_sd3077_write_disable();

    H_CC2640R2F_SimpleTime_Around_Delay(10);

    wdata[0] = 0;
    wdata[1] = 0;
    wdata[2] = 0;
    
    rslt += s_sd3077_iic_readbuff(S_SD3007_CLOCK_ALARM_SEC_ADDR, wdata, \
                                    3);

    // printf("0x%02x, %02x, %02x\r\n", wdata[0], wdata[1], wdata[2]);

    return rslt;
}


// signed char S_SD3077_SetInt_Hour_Min_Second(unsigned char hour, unsigned char min, unsigned char sec)
// {
//     signed char rslt = 0;

//     unsigned char wdata[3];
//     wdata[0] = S_SD3077_Byte2BCD(sec);
//     wdata[1] = S_SD3077_Byte2BCD(min);
//     wdata[2] = S_SD3077_Byte2BCD(hour);

//     // printf("the sec bcd is 0x%02x, addr is 0x%02x\r\n", wdata[0], S_SD3007_CLOCK_ALARM_SEC_ADDR);

//     rslt = s_sd3077_write_enable();
    
//     rslt += s_sd3077_iic_writebuff(S_SD3007_CLOCK_ALARM_SEC_ADDR, wdata, \
//                                     3);



//     rslt += s_sd3077_write_disable();

//     H_CC2640R2F_SimpleTime_Around_Delay(10);

//     wdata[0] = 0;
//     wdata[1] = 0;
//     wdata[2] = 0;
    
//     rslt += s_sd3077_iic_readbuff(S_SD3007_CLOCK_ALARM_SEC_ADDR, wdata, \
//                                     3);

//     // printf("0x%02x, %02x, %02x\r\n", wdata[0], wdata[1], wdata[2]);

//     return 0;
// }
         
signed char S_SD3077_Reset_RTC_Intr(unsigned int up_sec)
{
    // s_normaltime_str utc_str;

    // unsigned char tmp_sec = 0U;

    // S_SD3077_GetDateStr(&utc_str);

    // // printf("time now is %d:%d:%d\r\n", utc_str.hour, utc_str.min, utc_str.sec);

    // if(utc_str.sec + up_sec > 59)
    // {
    //     tmp_sec = utc_str.sec + up_sec - 59;
    //     if(utc_str.min >= 59)
    //     {
    //         if(utc_str.hour >= 23)
    //         {
    //             utc_str.hour = 0;
    //         }
    //         else
    //         {
    //             utc_str.hour += 1;
    //         }
    //         utc_str.min = 0;
    //         utc_str.sec = tmp_sec;
    //     }
    //     else
    //     {
    //         utc_str.min += 1;
    //         utc_str.sec = tmp_sec;
    //     }
    // }
    // else
    // {
    //     utc_str.sec += up_sec;
    // }

    // up_sec = utc_str.hour * 3600 + utc_str.min * 60 + utc_str.sec;

    up_sec += S_SD3077_Get_Time_Now_Second();

    

    printf("the new reset is %d\r\n", up_sec);

    
    // printf("set is %d:%d:%d\r\n", utc_str.hour, utc_str.min, utc_str.sec);



    S_SD3077_Clear_IntrFlag();

    S_SD3077_SetInt_Hour_Min_Second_ByDaySeconds(up_sec);
    S_SD3077_Set_ClockAlarmMode(sd3077_clock_alarm_only_enable_seconde_min_hour);


    if(up_sec >= SD3077_IMPOSSIBLE_TIME)
    {
        return (-1);
    }
    else
    {
        return 0;
    }
    
    // printf("Set alarm time %d\r\n", S_SD3077_SetInt_Hour_Min_Second(utc_str.hour, utc_str.min, utc_str.sec));
    // printf("Set clock alarm mode rslt %d\r\n", S_SD3077_Set_ClockAlarmMode(sd3077_clock_alarm_only_enable_seconde_min_hour));
}

unsigned int S_SD3077_Get_Time_Now_Second(void)
{
  unsigned int now_day_time_sec = 0U;

  s_normaltime_str nmt;

  if(S_SD3077_GetDateStr(&nmt))
  {
    // Try it again
    printf("read sd3077 str failed in get sec now\r\n");
    return SD3077_IMPOSSIBLE_TIME;
  }

  now_day_time_sec = nmt.hour * 3600 + nmt.min * 60 + nmt.sec;

  return now_day_time_sec;
}

void S_SD3077_Seconds_2_HMS(unsigned int sec, SD3077_HMS_Data *hms)
{
  hms->hour = sec / 3600;
  sec -= hms->hour * 3600;
  hms->min = sec / 60;
  sec -= hms->min * 60;
  hms->sec = sec;
}

void S_SD3077_Test(void)
{
//    unsigned char rdata = 0U;
    unsigned int utc = 0U;

    
    // // S_SD3077_GetDate(&utc);
    // S_SD3077_SetDate(1558081744);
    while(1)
    {
        S_SD3077_GetDate(&utc);
        s_sd3077_debug("The utc is %d\r\n", utc);
        H_CC2640R2F_SimpleTime_Around_Delay(1000);
    }

    // S_SD3077_Reset_RTC_Intr(5);



    // S_SD3077_Set_ClockAlarmMode_IntFlag_ReadClear_Mode();
    // S_SD3077_Clear_IntrFlag();

    // printf("Set alarm time %d\r\n", S_SD3077_SetInt_Hour_Min_Second(utc_str.hour, utc_str.min, utc_str.sec));
    // printf("Set clock alarm mode rslt %d\r\n", S_SD3077_Set_ClockAlarmMode(sd3077_clock_alarm_only_enable_seconde_min_hour));
    
    // while(1)
    // {
    //     s_sd3077_iic_readbuff(0x00, &rdata, 1);
    //     printf("0x%02x\r\n", rdata);
    //     H_CC2640R2F_SimpleTime_Around_Delay(1000);
    // }
    
}
